package cn.yunyichina.provider.pay.alipay.service.impl;

import cn.yunyichina.provider.iface.entity.alipay.AlipayRequest;
import cn.yunyichina.provider.iface.entity.common.ResCommon;
import cn.yunyichina.provider.iface.entity.common.ResponseObject;
import cn.yunyichina.provider.iface.entity.dto.pay.*;
import cn.yunyichina.provider.pay.alipay.config.Alipay;
import cn.yunyichina.provider.pay.alipay.constant.ResponseEnum;
import cn.yunyichina.provider.pay.alipay.entity.*;
import cn.yunyichina.provider.pay.alipay.entity.common.TradeRequest;
import cn.yunyichina.provider.pay.alipay.service.AlipayTradeService;
import cn.yunyichina.provider.pay.alipay.service.BaseTradeService;
import cn.yunyichina.utils.constants.Encoding;
import cn.yunyichina.utils.convert.JsonUtils;
import cn.yunyichina.utils.dozer.Dozer;
import cn.yunyichina.utils.json.Jackson;
import cn.yunyichina.utils.security.SignUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.net.URLEncoder;
import java.util.Map;

/**
 * Created by Lullaby on 2016/11/14.
 */
@Service
public class AlipayTradeServiceImpl extends BaseTradeService implements AlipayTradeService {

    private static final Logger logger = LoggerFactory.getLogger(AlipayTradeServiceImpl.class);

    /**
     * 支付宝扫码付
     *
     * @param json
     * @return
     */
    public ResponseObject precreateAlipayTrade(String json) {
        logger.info("AlipayTradeServiceImpl.precreateAlipayTrade.json -> {}", json);

        ResponseObject response = new ResponseObject();

        TradeRequest tradeRequest = JsonUtils.parseObject(json, TradeRequest.class);

        AlipayClient alipayClient = new DefaultAlipayClient(
                this.getConfig(Alipay.ALIPAY_GATEWAY_OPENAPI),
                tradeRequest.getAppId(),
                tradeRequest.getPrivateKey(),
                tradeRequest.getFormat(),
                tradeRequest.getCharset(),
                tradeRequest.getPublicKey(),
                tradeRequest.getSignType());

        AlipayTradePrecreateRequest alipayPrecreateRequest = new AlipayTradePrecreateRequest();
        alipayPrecreateRequest.setNotifyUrl(tradeRequest.getNotifyUrl());
        alipayPrecreateRequest.setBizContent(tradeRequest.getBizContent());
        logger.info("AlipayTradeServiceImpl.precreateAlipayTrade.alipayPrecreateRequest -> {}", JsonUtils.toJsonString(alipayPrecreateRequest));

        try {
            com.alipay.api.response.AlipayTradePrecreateResponse alipayPrecreateResponse = alipayClient.execute(alipayPrecreateRequest);
            logger.info("AlipayTradeServiceImpl.precreateAlipayTrade.alipayPrecreateResponse -> {}", JsonUtils.toJsonString(alipayPrecreateResponse));

            if (alipayPrecreateResponse.isSuccess()) {
                TradePrecreateResponse tradePrecreateResponse = JsonUtils.parseObject(alipayPrecreateResponse.getBody(), TradePrecreateResponse.class);
                TradePrecreateResponse.AlipayTradePrecreateResponse alipayTradePrecreateResponse = tradePrecreateResponse.getAlipayTradePrecreateResponse();

                response.setResultObject(alipayTradePrecreateResponse);
            } else {
                response.setResultCodeAndMessageAndResult(
                        ResponseEnum.ALIPAY_PAY_PRECREATE_FAILURE.getCode(),
                        ResponseEnum.ALIPAY_PAY_PRECREATE_FAILURE.getMessage(),
                        this.getTradeFailureResponse(alipayPrecreateResponse)
                );
            }
        } catch (AlipayApiException e) {
            logger.error("AlipayTradeServiceImpl.precreateAlipayTrade.AlipayApiException", e);
            response.setResultCodeAndMessage(
                    ResponseEnum.ALIPAY_PAY_PRECREATE_EXCEPTION.getCode(),
                    ResponseEnum.ALIPAY_PAY_PRECREATE_EXCEPTION.getMessage()
            );
        }

        return response;
    }

    /**
     * 支付宝手机网站支付
     *
     * @param json
     * @return
     */
    public ResponseObject wapAlipayTrade(String json) {
        logger.info("AlipayTradeServiceImpl.wapAlipayTrade.json -> {}", json);

        ResponseObject response = new ResponseObject();

        TradeWapRequest tradeWapRequest = JsonUtils.parseObject(json, TradeWapRequest.class);

        AlipayClient alipayClient = new DefaultAlipayClient(
                this.getConfig(Alipay.ALIPAY_GATEWAY_OPENAPI),
                tradeWapRequest.getAppId(),
                tradeWapRequest.getPrivateKey(),
                tradeWapRequest.getFormat(),
                tradeWapRequest.getCharset(),
                tradeWapRequest.getPublicKey(),
                tradeWapRequest.getSignType());

        AlipayTradeWapPayRequest alipayTradeWapPayRequest = new AlipayTradeWapPayRequest();

        String returnUrl = tradeWapRequest.getReturnUrl();
        if (!StringUtils.isEmpty(returnUrl)) {
            alipayTradeWapPayRequest.setReturnUrl(returnUrl);
        }
        alipayTradeWapPayRequest.setNotifyUrl(tradeWapRequest.getNotifyUrl());
        alipayTradeWapPayRequest.setBizContent(tradeWapRequest.getBizContent());

        try {
            logger.info("AlipayTradeServiceImpl.wapAlipayTrade.alipayTradeWapPayRequest -> {}", JsonUtils.toJsonString(alipayTradeWapPayRequest));
            AlipayTradeWapPayResponse alipayTradeWapPayResponse = alipayClient.pageExecute(alipayTradeWapPayRequest);
            logger.info("AlipayTradeServiceImpl.wapAlipayTrade.alipayTradeWapPayResponse -> {}", JsonUtils.toJsonString(alipayTradeWapPayResponse));

            if (alipayTradeWapPayResponse.isSuccess()) {
                String form = alipayTradeWapPayResponse.getBody();
                logger.info("AlipayTradeServiceImpl.wapAlipayTrade.form -> {}", form);

                TradeWapResponse tradeWapResponse = new TradeWapResponse();
                tradeWapResponse.setForm(form);

                response.setResultObject(tradeWapResponse);
            } else {
                response.setResultCodeAndMessageAndResult(
                        ResponseEnum.ALIPAY_PAY_WAP_FAILURE.getCode(),
                        ResponseEnum.ALIPAY_PAY_WAP_FAILURE.getMessage(),
                        this.getTradeFailureResponse(alipayTradeWapPayResponse)
                );
            }
        } catch (AlipayApiException e) {
            logger.error("AlipayTradeServiceImpl.wapAlipayTrade.AlipayApiException", e);
            response.setResultCodeAndMessage(
                    ResponseEnum.ALIPAY_PAY_WAP_EXCEPTION.getCode(),
                    ResponseEnum.ALIPAY_PAY_WAP_EXCEPTION.getMessage()
            );
        }

        return response;
    }

    /**
     * 支付宝APP支付
     *
     * @param json
     * @return
     */
    public ResponseObject appAlipayTrade(String json) {
        logger.info("AlipayTradeServiceImpl.appAlipayTrade.json -> {}", json);
        ResponseObject response = new ResponseObject();
        try {
            Map<String, String> paramsMap = JsonUtils.parseObject(json, Map.class);
            String privateKey = paramsMap.remove("private_key");

            String content = SignUtil.getAlipaySignContent(paramsMap);
            logger.info("AlipayTradeServiceImpl.appAlipayTrade.content -> {}", content);
            String sign;
            if ("RSA".equals(paramsMap.get("sign_type"))) {
                sign = AlipaySignature.rsaSign(content, privateKey, Encoding.UTF8);
            } else {
                sign = AlipaySignature.rsa256Sign(content, privateKey, Encoding.UTF8);
            }

            String encodedContent = SignUtil.getAlipayEncodedContent(paramsMap);
            String signedOrder = encodedContent.concat("&sign=").concat(URLEncoder.encode(sign, Encoding.UTF8));
            logger.info("AlipayTradeServiceImpl.appAlipayTrade.signedOrder -> {}", signedOrder);

            TradeAppResponse tradeAppResponse = new TradeAppResponse();
            tradeAppResponse.setSignedOrder(signedOrder);

            response.setResultObject(tradeAppResponse);
        } catch (Exception e) {
            logger.error("AlipayTradeServiceImpl.appAlipayTrade.Exception", e);
        }

        return response;
    }

    /**
     * 支付宝当面付(条码支付/声波支付)
     *
     * @param json
     * @return
     */
    public ResponseObject faceAlipayTrade(String json) {
        logger.info("AlipayTradeServiceImpl.faceAlipayTrade.json -> {}", json);

        ResponseObject response = new ResponseObject();

        TradeFaceRequest tradeFaceRequest = JsonUtils.parseObject(json, TradeFaceRequest.class);

        AlipayClient alipayClient = new DefaultAlipayClient(
                this.getConfig(Alipay.ALIPAY_GATEWAY_OPENAPI),
                tradeFaceRequest.getAppId(),
                tradeFaceRequest.getPrivateKey(),
                tradeFaceRequest.getFormat(),
                tradeFaceRequest.getCharset(),
                tradeFaceRequest.getPublicKey(),
                tradeFaceRequest.getSignType());

        AlipayTradePayRequest alipayTradePayRequest = new AlipayTradePayRequest();
        alipayTradePayRequest.setBizContent(tradeFaceRequest.getBizContent());
        logger.info("AlipayTradeServiceImpl.faceAlipayTrade.alipayTradePayRequest -> {}", JsonUtils.toJsonString(alipayTradePayRequest));

        try {
            AlipayTradePayResponse alipayTradePayResponse = alipayClient.execute(alipayTradePayRequest);
            logger.info("AlipayTradeServiceImpl.faceAlipayTrade.alipayTradePayResponse -> {}", JsonUtils.toJsonString(alipayTradePayResponse));

            if (alipayTradePayResponse.isSuccess()) {
                TradeFacePayResponse tradeFacePayResponse = JsonUtils.parseObject(alipayTradePayResponse.getBody(), TradeFacePayResponse.class);
                TradeFacePayResponse.AlipayTradeFacePayResponse alipayTradeFacePayResponse = tradeFacePayResponse.getAlipayTradePayResponse();

                response.setResultObject(alipayTradeFacePayResponse);
            } else {
                response.setResultCodeAndMessageAndResult(
                        ResponseEnum.ALIPAY_PAY_FACE_FAILURE.getCode(),
                        ResponseEnum.ALIPAY_PAY_FACE_FAILURE.getMessage(),
                        this.getTradeFailureResponse(alipayTradePayResponse)
                );
            }
        } catch (AlipayApiException e) {
            logger.error("AlipayTradeServiceImpl.faceAlipayTrade.AlipayApiException", e);
            response.setResultCodeAndMessage(
                    ResponseEnum.ALIPAY_PAY_FACE_EXCEPTION.getCode(),
                    ResponseEnum.ALIPAY_PAY_FACE_EXCEPTION.getMessage()
            );
        }

        return response;
    }

    /**
     * 支付宝当面付(条码支付/声波支付)
     *
     * @param requestDTO
     * @return
     */
    public ResCommon<AlipayBarPayResponseDTO> alipayBarPay(AlipayBarPayRequestDTO requestDTO) {
        AlipayClient alipayClient = new DefaultAlipayClient(
                this.getConfig(Alipay.ALIPAY_GATEWAY_OPENAPI),
                requestDTO.getAppId(),
                requestDTO.getPrivateKey(),
                requestDTO.getFormat(),
                requestDTO.getCharset(),
                requestDTO.getPayPublicKey(),
                requestDTO.getSignType()
        );

        AlipayTradePayRequest payRequest = new AlipayTradePayRequest();
        payRequest.setBizContent(requestDTO.getBizContent());
        logger.info("AlipayTradeServiceImpl.barpayAlipayTrade.payRequest -> {}", Jackson.toJson(payRequest));

        ResCommon<AlipayBarPayResponseDTO> response = new ResCommon<>();
        try {
            AlipayTradePayResponse payResponse = alipayClient.execute(payRequest);
            logger.info("AlipayTradeServiceImpl.barpayAlipayTrade.payResponse -> {}", Jackson.toJson(payResponse));

            if (payResponse.isSuccess()) {
                TradeFacePayResponse tradeFacePayResponse = JsonUtils.parseObject(payResponse.getBody(), TradeFacePayResponse.class);
                assert tradeFacePayResponse != null;
                TradeFacePayResponse.AlipayTradeFacePayResponse alipayTradeFacePayResponse = tradeFacePayResponse.getAlipayTradePayResponse();
                response.buildResult(Dozer.convert(alipayTradeFacePayResponse, AlipayBarPayResponseDTO.class));
            } else {
                response.setResultCodeAndMessageAndResult(
                        ResponseEnum.ALIPAY_PAY_FACE_FAILURE.getCode(),
                        ResponseEnum.ALIPAY_PAY_FACE_FAILURE.getMessage(),
                        setCodeAndMessage(payResponse, AlipayBarPayResponseDTO.class)
                );
            }
        } catch (Exception e) {
            logger.error("AlipayTradeServiceImpl.barpayAlipayTrade.Exception", e);
            response.setResultCodeAndMessage(
                    ResponseEnum.ALIPAY_PAY_FACE_EXCEPTION.getCode(),
                    ResponseEnum.ALIPAY_PAY_FACE_EXCEPTION.getMessage()
            );
        }

        return response;
    }

    /**
     * 查询支付宝支付订单
     *
     * @param queryRequest
     * @return
     */
    public ResCommon<AlipayOrderQueryResponseDTO> queryAlipayOrder(AlipayOrderQueryRequestDTO queryRequest) {
        ResCommon<AlipayOrderQueryResponseDTO> queryResponse = new ResCommon<>();

        AlipayClient alipayClient = new DefaultAlipayClient(
                getConfig(Alipay.ALIPAY_GATEWAY_OPENAPI),
                queryRequest.getAppId(),
                queryRequest.getPrivateKey(),
                queryRequest.getFormat(),
                queryRequest.getCharset(),
                queryRequest.getPublicKey(),
                queryRequest.getSignType()
        );

        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        request.setBizContent(queryRequest.getBizContent());
        logger.info("AlipayTradeServiceImpl.queryAlipayOrder.request -> {}", JSON.toJSONString(request));

        try {
            AlipayTradeQueryResponse response = alipayClient.execute(request);
            logger.info("AlipayTradeServiceImpl.queryAlipayOrder.response -> {}", JSON.toJSONString(response));

            if (response.isSuccess()) {
                queryResponse.setResult(JsonUtils.parseObject(response.getBody(), AlipayOrderQueryResponseDTO.class));
            } else {
                queryResponse.setResultCodeAndMessage(
                        ResponseEnum.ALIPAY_QUERY_FAILURE.getCode(),
                        ResponseEnum.ALIPAY_QUERY_FAILURE.getMessage()
                );
            }
        } catch (AlipayApiException e) {
            logger.error("AlipayTradeServiceImpl.queryAlipayOrder.AlipayApiException", e);
            queryResponse.setResultCodeAndMessage(
                    ResponseEnum.ALIPAY_QUERY_EXCEPTION.getCode(),
                    ResponseEnum.ALIPAY_QUERY_EXCEPTION.getMessage()
            );
        }

        return queryResponse;
    }

    /**
     * 撤销支付宝支付订单
     *
     * @param cancelRequest
     * @return
     */
    public ResCommon<AlipayOrderCancelResponseDTO> cancelAlipayOrder(AlipayOrderCancelRequestDTO cancelRequest) {
        ResCommon<AlipayOrderCancelResponseDTO> cancelResponse = new ResCommon<>();

        AlipayClient alipayClient = new DefaultAlipayClient(
                getConfig(Alipay.ALIPAY_GATEWAY_OPENAPI),
                cancelRequest.getAppId(),
                cancelRequest.getPrivateKey(),
                cancelRequest.getFormat(),
                cancelRequest.getCharset(),
                cancelRequest.getPublicKey(),
                cancelRequest.getSignType()
        );

        AlipayTradeCancelRequest request = new AlipayTradeCancelRequest();
        request.setBizContent(cancelRequest.getBizContent());
        logger.info("AlipayTradeServiceImpl.cancelAlipayOrder.request -> {}", JSON.toJSONString(request));

        try {
            AlipayTradeCancelResponse response = alipayClient.execute(request);
            logger.info("AlipayTradeServiceImpl.cancelAlipayOrder.response -> {}", JSON.toJSONString(response));

            if (response.isSuccess()) {
                cancelResponse.setResult(JsonUtils.parseObject(response.getBody(), AlipayOrderCancelResponseDTO.class));
            } else {
                cancelResponse.setResultCodeAndMessage(
                        ResponseEnum.ALIPAY_CANCEL_FAILURE.getCode(),
                        ResponseEnum.ALIPAY_CANCEL_FAILURE.getMessage()
                );
            }
        } catch (AlipayApiException e) {
            logger.error("AlipayTradeServiceImpl.cancelAlipayOrder.AlipayApiException", e);
            cancelResponse.setResultCodeAndMessage(
                    ResponseEnum.ALIPAY_CANCEL_EXCEPTION.getCode(),
                    ResponseEnum.ALIPAY_CANCEL_EXCEPTION.getMessage()
            );
        }

        return cancelResponse;
    }

    /**
     * 支付宝医疗信息报备(0元医保挂号)
     *
     * @param alipayRequest
     * @return
     */
    public ResCommon<AlipayMedInfoUploadResponseDTO> alipayMedInfoUpload(AlipayRequest alipayRequest) {
        AlipayClient alipayClient = new DefaultAlipayClient(
                getConfig(Alipay.ALIPAY_GATEWAY_OPENAPI),
                alipayRequest.getAppId(),
                alipayRequest.getPrivateKey(),
                alipayRequest.getFormat(),
                alipayRequest.getCharset(),
                alipayRequest.getPublicKey(),
                alipayRequest.getSignType()
        );

        AlipayCommerceMedicalInformationUploadRequest request = new AlipayCommerceMedicalInformationUploadRequest();
        request.setBizContent(alipayRequest.getBizContent());
        logger.info("AlipayTradeServiceImpl.alipayMedInfoUpload.request -> {}", JSON.toJSON(request));

        try {
            AlipayCommerceMedicalInformationUploadResponse response = alipayClient.execute(request);
            logger.info("AlipayTradeServiceImpl.alipayMedInfoUpload.response -> {}", JSON.toJSON(response));

            if (response.isSuccess()) {
                return new ResCommon<AlipayMedInfoUploadResponseDTO>().buildResult(Dozer.convert(response, AlipayMedInfoUploadResponseDTO.class));
            } else {
                return new ResCommon<AlipayMedInfoUploadResponseDTO>().buildResultCodeAndMessage(
                        ResponseEnum.ALIPAY_MEDINFO_UPLOAD_FAIL.getCode(),
                        ResponseEnum.ALIPAY_MEDINFO_UPLOAD_FAIL.getMessage()
                );
            }
        } catch (AlipayApiException e) {
            logger.error("AlipayTradeServiceImpl.alipayMedInfoUpload.AlipayApiException", e);
            return new ResCommon<AlipayMedInfoUploadResponseDTO>().buildResultCodeAndMessage(
                    ResponseEnum.ALIPAY_MEDINFO_UPLOAD_EXCEPTION.getCode(),
                    ResponseEnum.ALIPAY_MEDINFO_UPLOAD_EXCEPTION.getMessage()
            );
        }
    }

}
